/* Header file of LineAnalyzer. This module is responsible for receiving a text line and convert it to LineStruct */

#include "Common.h"

#define FIRST_OPERAND 0 /* Index of first operand */
#define SECOND_OPERAND 1 /* Index of second operand */
#define MAX_LINE_LENGTH 80 /* Maximum length of the line */
#define MAX_ADDITIONAL_WORDS 4 /* Maximum additional words */
#define MAX_NUMBER_OF_OPERANDS 2 /* Maximum number of operands */
#define NUMBER_OF_ERRORS	28	/*Amount of errors */
#define MAX_ERROR_DESCRIPTION_LENGTH	100 /* Maximum length of error */
#define NUMBER_OF_COMMANDS 16					/* Number of commands */

/* Line type, it can be operation or command */
typedef enum LINE_TYPE_e
{
	OPERATION,
	COMMAND
}LINE_TYPE;

/* Type of operation */
typedef enum OPERATION_TYPE_e
{
	OPERATION_NONE,
	OPERATION_DATA,
	OPERATION_STRING,
	OPERATION_ENTRY,
	OPERATION_EXTERN
}OPERATION_TYPE;

/* Type of command */
typedef enum COMMAND_TYPE_e
{
	COMMAND_NONE = -1,
	COMMAND_MOV = 0,
	COMMAND_CMP = 1,
	COMMAND_ADD = 2,
	COMMAND_SUB = 3,
	COMMAND_NOT = 4,
	COMMAND_CLR = 5,
	COMMAND_LEA = 6,
	COMMAND_INC = 7,
	COMMAND_DEC = 8,
	COMMAND_JMP = 9,
	COMMAND_BNE = 10,
	COMMAND_RED = 11,
	COMMAND_PRN = 12,
	COMMAND_JSR = 13,
	COMMAND_RTS = 14,
	COMMAND_STOP = 15
}COMMAND_TYPE;

/* Type of address */
typedef enum ADDRESS_TYPE_e
{
	ADDRESS_IMMIDIATE,
	ADDRESS_DIRECT,
	ADDRESS_INDEX,
	ADDRESS_REGISTER_DIRECT
}ADDRESS_TYPE;

/* Type of index address */
typedef enum ADDRESS_INDEX_TYPE_e
{
	INDEX_LABEL,
	INDEX_NUMBER,
	INDEX_REGISTER
}ADDRESS_INDEX_TYPE;

/* Combination bit type */
typedef enum COMBINATION_e
{
	LEFT_BITS_SRC_LEFT_BITS_DST,
	LEFT_BITS_SRC_RIGHT_BITS_DST,
	RIGHT_BITS_SRC_LEFT_BITS_DST,
	RIGHT_BITS_SRC_RIGHT_BITS_DST
}COMBINATION;

/* Type of error */
typedef enum ERROR_TYPE_e
{
	ERROR_NONE,
	ERROR_LINE_LENGTH_EXCEEDS_80_CHARS,
	ERROR_ILLEGAL_LABEL_LENGTH,
	ERROR_ILLEGAL_LABEL_SYNTAX,
	ERROR_ILLEGAL_LABEL_COMMAND_NAME,
	ERROR_ILLEGAL_LABEL_REGISTER_NAME,
	ERROR_ILLEGAL_OPERATION,
	ERROR_ILLEGAL_DATA_PARAMETER_TYPE,
	ERROR_ILLEGAL_DATA_AT_LEAST_ONE_PARAMETER,
	ERROR_ILLEGAL_STRING_PARAMETER,
	ERROR_ILLEGAL_ENTRY_LABEL_NAME,
	ERROR_ILLEGAL_ENTRY_LABEL_LENGTH,
	ERROR_ILLEGAL_EXTERN_LABEL_NAME,
	ERROR_ILLEGAL_EXTERN_LABEL_LENGTH,
	ERROR_ILLEGAL_COMMAND,
	ERROR_ILLEGAL_NUMBER_OF_OPERANDS_EXPECTED_ZERO_OPERANDS,
	ERROR_ILLEGAL_NUMBER_OF_OPERANDS_EXPECTED_ONE_OPERAND,
	ERROR_ILLEGAL_NUMBER_OF_OPERANDS_EXPECTED_TWO_OPERANDS,
	ERROR_ILLEGAL_OPERAND_TYPE,
	ERROR_ILLEGAL_ADDRESS_TYPE,
	ERROR_ILLEGAL_DIRECT_ADDRESS_TO_DESTINATION,
	ERROR_ILLEGAL_ADDRESS_LABEL,
	ERROR_ILLEGAL_ADDRESS_INDEX_FORMAT,
	ERROR_ILLEGAL_DBL_IN_COMMAND,
	ERROR_ILLEGAL_DBL_VALUE,
	ERROR_ILLEGAL_LABEL_IS_NOT_DEFINED,
	ERROR_ILLEGAL_LABEL_IS_DEFINED_MORE_THEN_ONCE,
	ERROR_ILLEGAL_ADDRESS_TYPE_FOR_THE_COMMAND
}ERROR_TYPE;

/* Array that contains all the commands */
const char ERRORS_TEXT[NUMBER_OF_ERRORS][MAX_ERROR_DESCRIPTION_LENGTH] = 
{ "",
	"Line length exceeds 80 characters",
	"Illegal label length",
	"Illegal label syntax",
	"Illegal label name - the name is reserved for a command",
	"Illegal label name - the name is reserved for a register",
	"Illegal operation",
	"Illegal data parameter type",
	"At lease one parameter should be defined in data operation",
	"Illegal string parameter",
	"Illegal label is defined for an entry",
	"Illegal label length is defined for an entry",
	"Illegal label is defined for an extern",
	"Illegal label length is defined for an extern",
	"Illegal command",
	"Illegal number of operands, no operands were expected" ,
	"Illegal number of operands, only one operand was expected" ,
	"Illegal number of operands, only two operands were expected" ,
	"Ilegal operand type",
	"Illegal address type for operand",
	"Direct address cannot be for destination operand",
	"Illegal address label for operand",
	"Address index format is illegal",
	"Illegal dbl format",
	"Illegal dbl value",
	"Usage of label that is not defined",
	"Label is defined more than once",
	"Illegal address type for command"
	};


/* Array that contains legal number of operands per command */
const int COMMANDS_OPERANDS_ARRAY[NUMBER_OF_COMMANDS] = 
{ 2,2,2,2,1,1,2,1,1,1,1,1,1,1,0,0};

/* Operation structure - contains a union of int array, string */
typedef struct Operation_s
{
	OPERATION_TYPE operationType; /* Operation type */
	int dataLength;					/* Data length of the array/string */

	union
	{
		int intData[MAX_LINE_LENGTH]; /* For Data */
		char stringData[MAX_LINE_LENGTH]; /* For String, Extern, Entry */
	} uData;
}Operation;

/* Command structure */
typedef struct Command_s
{
	COMBINATION operandCombinationType; /* comb - combination bits */
	int registers[MAX_NUMBER_OF_OPERANDS]; /* first cell - source. second cell - destination. If there is only one cell it is destination */
	ADDRESS_TYPE addresses[MAX_NUMBER_OF_OPERANDS]; /* first cell - source. second cell - destination. If there is only one cell it is destination */
	ADDRESS_INDEX_TYPE addressIndexes[MAX_NUMBER_OF_OPERANDS]; /* first cell - source. second cell - destination. If there is only one cell it is destination */
	
	COMMAND_TYPE commandType; /* Type of the command */
	int operandNumberBitsType; /* 0 - 20 bits. 1 - 10 bits */
	int dbl; /* Dble bit. 0 - Regular. 1 - Double */
	int additionalWordsCount; /* Number of additional words in the line */
	char additionalWords[MAX_ADDITIONAL_WORDS][MAX_LINE_LENGTH]; /* Additional words data */
	
}Command;

/* Line structure */
typedef struct LineStruct_s
{
	char label[MAX_LINE_LENGTH]; /* Label */
	LINE_TYPE linetype; /* Type of the line */
	ERROR_TYPE error; /* Error if exists in the line */
	int lineNumber; /* Number of line - used for error writing */
	int machineCode;
	/* It can be an operation or command */
	union
	{
		Operation sOperation;
		Command sCommand;
	}uLine;
}LineStruct;

/*********************************************************************************************************************** */
/* Description: Main fuction for analyzing line */
/* Input: line - line text to analyze
/* Input/Output: pLineStruct - Line struct after the line was analyzed
/*********************************************************************************************************************** */
void AnalyzeLine(char* line, LineStruct *pLineStruct);

/*********************************************************************************************************************** */
/* Description: Transform a command to its numeric format by bits mnipulation
/* Input: commandStruct - line structure, from here I take all necessary information of the command 
/* Output: Return the command represented as number
/*********************************************************************************************************************** */
int produceMachineCode(Command* command);